module dig_sm (clk,rst_n,accel_vld,eep_cs_n,eep_r_w_n,eep_addr,src0sel,src1sel,cmplmnt,saturate,
		   dst2P,dst2R,dst2Err,dst2PrevErr,dst2SumErr,dst2DutyWrk,dst2Xset,wrt_duty,
		   BoothSel,chrg_pmp_en,cfg_data,strt_tx,clr_rdy,frm_rdy); 

input clk,rst_n,accel_vld;
input [1:0] BoothSel;
input [3:0] cfg_data;
input frm_rdy;
output reg clr_rdy,strt_tx;
output reg eep_cs_n,eep_r_w_n,saturate;
output reg chrg_pmp_en;
output reg [1:0] eep_addr;

/////// Type defs for SRC bus selects //////////////
typedef enum logic [2:0] {PrevErr2Src0, SumErr2Src0, DutyWrk2Src0, EEP2Src0,
                          Xset2Src0, posAck2Src0, zero2Src0} src0sel_t;
typedef enum logic [2:0] {P2Src1, MultRes2Src1, Xmeas2Src1, CfgData2Src1,
                          Err2Src1, zero2Src1} src1sel_t;
output src0sel_t src0sel;
output src1sel_t src1sel;
output logic cmplmnt,dst2P,dst2R,dst2Err,dst2PrevErr,dst2SumErr;
output logic dst2DutyWrk,wrt_duty,dst2Xset;

typedef enum reg [3:0] {LD_XSET, WAIT_ACCEL_VLD, CALCERR, PMULTERR, SUMERR, IMULTSUMERR,
                        DERR, DMULTERR, DUTYUNSIGN, PREVERR, XSET, CMDINTR,
			CHRGPMP, WAITCMD} state_t;

state_t state, nxt_state;

////////////////////////////////////////
// EEPROM address locations/meanings //
//////////////////////////////////////
localparam SetPt = 2'b00;
localparam Pterm = 2'b01;
localparam Iterm = 2'b10;
localparam Dterm = 2'b11;

////////////////////////
// Command encodings //
//////////////////////
localparam CMD_MD  = 4'b0011;
localparam RD_EEP  = 4'b01xx;
localparam WRT_EEP = 4'b10xx;
localparam NewXset = 4'b1100;


/////////////////////////
//State assignment
////////////////////////
always @(posedge clk, negedge rst_n) begin
	if(!rst_n)
		state <= LD_XSET;
	else
		state <= nxt_state;
end

//////////////////////////////
//posedge accel detector
//////////////////////////////
reg temp_accel;

always @(posedge clk)
	temp_accel <= accel_vld;

assign accel_became_vld = (!temp_accel & accel_vld);


///////////////////////////////
//multiply count number
///////////////////////////////

reg [3:0] mult_numb;
logic mult_cnt, clr_mult_cnt;
localparam TOP = 4'b1110;

always @(posedge clk, negedge rst_n) begin
	if(!rst_n)
		mult_numb <= 4'h0;
	else if(mult_cnt)
		mult_numb <= mult_numb + 1;
	else if(clr_mult_cnt)
		mult_numb <= 4'h0;
end

///////////////////////////////
//3ms timer counter
///////////////////////////////

reg [21:0] timer_counter;
logic timer_count, clr_timer;

always @(posedge clk, negedge rst_n) begin
	if(!rst_n)
		timer_counter <= 22'h000000;
	else if(timer_count)
		timer_counter <= timer_counter + 1;
	else if(clr_timer)
		timer_counter <= 22'h000000;
end


///////////////////////////////
//in_CM FLOP
///////////////////////////////

reg in_CM;
logic set_in_CM;

always @(posedge clk, negedge rst_n) begin
	if(!rst_n)
		in_CM <= 1'b0;
	else if(set_in_CM)
		in_CM <= 1'b1;
end



//////////////////////////////////
//STATE MACHINE COMBINATIONAL
//////////////////////////////////
always_comb begin

	nxt_state = LD_XSET;
	src0sel = zero2Src0;
	src1sel = zero2Src1;


//default parameters	
	cmplmnt = 0;
	dst2P = 0;
	dst2R = 0;
	dst2Err = 0;
	dst2PrevErr = 0;
	dst2SumErr = 0;
	dst2DutyWrk = 0;
	wrt_duty = 0;
	dst2Xset = 0;
	clr_rdy = 0;
	strt_tx = 0;
	eep_cs_n = 1;
	eep_r_w_n = 1;
	saturate = 0;
	chrg_pmp_en = 0;
	eep_addr = 2'b00;
	clr_timer = 0;
	timer_count = 0;	
	set_in_CM = 0;
	clr_mult_cnt = 0;
	mult_cnt = 0;	

	
	case(state)
		LD_XSET: begin	
			nxt_state = LD_XSET;
		
			///////////////////////////////
			//sumerr = 0
			//PrevErr = 0
			//Xset = eeprom
			///////////////////////////////
		
			mult_cnt = 1;
			if(mult_numb == 4'h0)
				dst2SumErr = 1;
			else if(mult_numb == 4'h1)
				dst2PrevErr = 1;
			else if(mult_numb == 4'h2)begin
				//eeprom address == 00
				eep_cs_n = 0;
				src0sel = EEP2Src0;
				dst2Xset = 1;
				clr_mult_cnt = 1;
				nxt_state = WAIT_ACCEL_VLD;
			end
		end

		WAIT_ACCEL_VLD: begin
		
		        nxt_state = WAIT_ACCEL_VLD;
			
	
			if(accel_became_vld)
				nxt_state = CALCERR;	//begin calculations if posedge accel_vld



                end
		CALCERR: begin
			
			//////////////////////////////
			//ERR = Xmeas - Xset
			/////////////////////////////		        
			src0sel = Xset2Src0;
			src1sel = Xmeas2Src1;
			cmplmnt = 1;
			dst2Err = 1;
			dst2R = 1; 
			clr_mult_cnt = 1;
			saturate = 1;
			nxt_state = PMULTERR;	




                end
		PMULTERR: begin
			
		        nxt_state = PMULTERR;
			
			mult_cnt = 1;		//starts count
			eep_addr = 2'b01;	//reads from P vaule in eeprom
			eep_cs_n = 0;
			/*if(mult_numb == 4'h0) begin	//load error into R reg
							
				src1sel = Err2Src1;	//src0 = zero
				dst2R = 1;

			end else 
			*/ if( mult_numb == TOP )begin

				src1sel = MultRes2Src1;	//if done, [25:12] of P reg for resule
				nxt_state = SUMERR;	//clears multiply and saturate
				clr_mult_cnt = 1;	//stores into duty
				saturate = 1;
				//wrt_duty
				dst2DutyWrk = 1;

			end else begin
				
				dst2P = 1;		//loads into P reg	
				src1sel = P2Src1;	//adds or subtracts eeprom from P side of register
				case(BoothSel)
					2'b01:
						src0sel = EEP2Src0;
					2'b10: begin
						src0sel = EEP2Src0; 
						cmplmnt = 1;
					end
					default:
						src0sel = zero2Src0;
				
				endcase

			end

                end
		SUMERR: begin
		        
                        //////////////////////////////
                        //SumErr = SumErr + Err
                        /////////////////////////////
                        src0sel = SumErr2Src0;
                        src1sel = Err2Src1;
                        //cmplmnt = 0;
                        dst2SumErr = 1;
                        dst2R = 1;
                        clr_mult_cnt = 1;
						saturate = 1;

			nxt_state = IMULTSUMERR;



                end
		IMULTSUMERR: begin
			//////////////////////////////
			//Duty = Duty + I*SumErr
			/////////////////////////////
		        nxt_state = IMULTSUMERR;

                        mult_cnt = 1;           //starts count
                        eep_addr = 2'b10;       //reads from P vaule in eeprom
			eep_cs_n = 0;
                        if( mult_numb == TOP )begin

                                src1sel = MultRes2Src1; //if done, [25:12] of P reg for resule
				src0sel = DutyWrk2Src0;
				///////////////////////////////////
				// Duty = Duty + MULT
				///////////////////////////////////
                                nxt_state = DERR;       //clears multiply and saturate
                                clr_mult_cnt = 1;       //stores into duty
                                saturate = 1;
                                //wrt_duty
                                dst2DutyWrk = 1;

                        end else begin

                                dst2P = 1;              //loads into P reg
                                src1sel = P2Src1;       //adds or subtracts eeprom from P side of register
                                case(BoothSel)
                                        2'b01:
                                                src0sel = EEP2Src0;
                                        2'b10: begin
                                                src0sel = EEP2Src0;
                                                cmplmnt = 1;
                                        end
                                        default:
                                                src0sel = zero2Src0;

                                endcase


			end

                end
                DERR: begin			
                        //////////////////////////////
                        //ERR = Xmeas - Xset
                        /////////////////////////////
                        src0sel = PrevErr2Src0;
                        src1sel = Err2Src1;
                        cmplmnt = 1;
                        //dst2SumErr = 1;
                        dst2R = 1;
                        clr_mult_cnt = 1;
						saturate = 1;
                        nxt_state = DMULTERR;





                end
                DMULTERR: begin
                        nxt_state = DMULTERR;
                        //////////////////////////////
                        //Duty = Duty + I*SumErr
                        /////////////////////////////

                        mult_cnt = 1;           //starts count
                        eep_addr = 2'b11;       //reads from P vaule in eeprom
			eep_cs_n = 0;
			
                        if( mult_numb == TOP )begin

                                src1sel = MultRes2Src1; //if done, [25:12] of P reg for resule
                                src0sel = DutyWrk2Src0;
                                ///////////////////////////////////
                                // Duty = Duty + MULT
                                ///////////////////////////////////

				//THIS MIGHT BE DUTYUNSIGN, I HAVE NO IDEA WHAT DUTYUNSIGN COULD DO
                                nxt_state = PREVERR;       //clears multiply and saturate
                                clr_mult_cnt = 1;       //stores into duty
                                saturate = 1;
                                dst2DutyWrk = 1;
				

				//////////////////////////////////
				//WRITE TO PWM
				//////////////////////////////////
				
				wrt_duty = 1;


                        end else begin

                                dst2P = 1;              //loads into P reg
                                src1sel = P2Src1;       //adds or subtracts eeprom from P side of register
                                case(BoothSel)
                                        2'b01:
                                                src0sel = EEP2Src0;
                                        2'b10: begin
                                                src0sel = EEP2Src0;
                                                cmplmnt = 1;
                                        end
                                        default:
                                                src0sel = zero2Src0;

                                endcase

			end


                end
		DUTYUNSIGN: begin
		/*
		        nxt_state = DUTYUNSIGN;
			src0sel = DutyWrk2Src0;
			wrt_duty			
		*/


                end
		PREVERR: begin
		        ///////////////////////////
			//PrevErr = Err
			///////////////////////////
			
			dst2PrevErr = 1;
			src1sel = Err2Src1;
			
			if(!frm_rdy)
				nxt_state = WAIT_ACCEL_VLD;			
			else if(cfg_data == NewXset)
				nxt_state = XSET;
			else
				nxt_state = CMDINTR;


                end
		XSET: begin

			//////////////////////////
			//Update and Echo
			//////////////////////////
		    	nxt_state = XSET;
			src1sel = CfgData2Src1;
			dst2Xset = 1;
			strt_tx = 1;
			clr_rdy = 1;
			nxt_state = WAIT_ACCEL_VLD;


                end
		CMDINTR: begin
		        nxt_state = CMDINTR;
			clr_rdy = 1;
			
			casex(cfg_data)
				
				WRT_EEP: begin
					
					if( in_CM) begin
						eep_r_w_n = 0;
						eep_cs_n = 0;
						eep_addr = cfg_data[1:0];
						src1sel = CfgData2Src1;
						nxt_state = CHRGPMP;	
					end
				end
				RD_EEP: begin
					
					if( in_CM) begin
						//eep read
						eep_cs_n = 0;
						eep_addr = cfg_data[1:0];
						src0sel = EEP2Src0;
						strt_tx = 1;
						
						nxt_state = WAITCMD;

					end
				end
				CMD_MD: begin
					strt_tx = 1;
					src0sel = posAck2Src0;
					set_in_CM = 1;
					nxt_state = WAITCMD;

				end
				default:begin
					
					src0sel = posAck2Src0;
					cmplmnt = 1;
					strt_tx = 1;
					nxt_state = WAITCMD;
					
				end
			endcase
                end
		CHRGPMP: begin
		        nxt_state = CHRGPMP;
			
			chrg_pmp_en = 1;
			timer_count = 1;
			if(timer_counter == 22'h249F00) begin
				nxt_state = WAITCMD;
				clr_timer = 1;

				src0sel = posAck2Src0;
				strt_tx = 1;
                	end
		end
		WAITCMD: begin
		        nxt_state = WAITCMD;
			
			if(frm_rdy)
				nxt_state = CMDINTR;



                end
	endcase
end


	






endmodule	
	

